home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / choices / choicess.lha / CPU.c < prev    next >
C/C++ Source or Header  |  1989-02-06  |  11KB  |  481 lines

  1. /*
  2.  * This file is part of the Choices Operating System Simulator
  3.  * Developed by: The TAPESTRY Parallel Computing Laboratory
  4.  *         University of Illinois at Urbana-Champaign
  5.  *         Department of Computer Science
  6.  *         1304 W. Springfield Ave.
  7.  *         Urbana, IL    61801
  8.  *
  9.  * Copyright (c) 1987, 1988, 1989 The University of Illinois Board of Trustees.
  10.  *    All Rights Reserved.
  11.  * CONFIDENTIAL INFORMATION. Distribution restricted under license agreement.
  12.  *
  13.  * Author: Gary M. Johnston (johnston@cs.uiuc.edu)
  14.  * Project Manager and Principal Investigator: Roy Campbell (roy@cs.uiuc.edu)
  15.  *
  16.  * Funded by: NSF TAPESTRY Grant No. 1-5-30035, NASA ICLASS Grant 
  17.  *   No. 1-5-25469 and No. NSG1471 and AT&T Metronet Grant No. 1-5-37411.
  18.  */
  19. /*
  20.  *    CPU.c - Implementation of classes CPUTimer, CPUManager, and CPU.
  21.  *        Implementation of ThisCPU().
  22.  *
  23.  *    $Header: CPU.c,v 1.4 88/02/18 16:13:08 johnston Exp $
  24.  *    $Locker: johnston $
  25.  */
  26.  
  27. #include "task.h"
  28. #include "Assert.h"
  29. #include "Debug.h"
  30. #include "Debug.h"
  31. #include "Clock.h"
  32. #include "Name.h"
  33. #include "CPU.h"
  34. #include "Process.h"
  35. #include "Vector.h"
  36. #include "Exception.h"
  37. #include "SoftwareException.h"
  38.  
  39. CPUTimer::CPUTimer( CPU * cpu, int ticks )
  40.     : ( CatName( CatName( MakeName( "CPUTimer", this ), " for " ),
  41.              cpu->getName() ) )
  42. {
  43.     Debug("%s: Ctor (%d ticks).\n", getName(), ticks);
  44.     Assert(cpu != 0);
  45.     Assert(ticks > 0);
  46.  
  47.     /*
  48.      * Initialize.
  49.      */
  50.     stopped = 0;
  51.  
  52.     /*
  53.      * Start the timer and wait for it.
  54.      * Interrupt the CPU when time is up, unless we were stopped.
  55.      */
  56.     t = new timer( ticks );
  57.     (void) t->result();
  58.     if ( ! stopped ) {
  59.         Debug("%s::ctor interrupting %s.\n", getName(), cpu->getName());
  60.         cpu->interrupt(TimerVector);
  61.     }
  62.     resultis(0);
  63.     NotReached();
  64. }
  65.  
  66. CPUTimer::~CPUTimer()
  67. {
  68.     Assert(rdstate() == TERMINATED);
  69.     Assert(t->rdstate() == TERMINATED);
  70. }
  71.  
  72. int
  73. CPUTimer::stop()
  74. {
  75.     /*
  76.      * Cancel the timer.
  77.      * Wait for the task.
  78.      * Return the time that was left.
  79.      */
  80.     int residual = t->rdtime() - clock;
  81.     stopped = 1;
  82.     if ( residual < 0 )
  83.         Debug("%s::stop %d - %d < 0\n", getName(), t->rdtime(), clock);
  84.     Assert(residual >= 0);
  85.     Debug("%s::stop.\n", getName());
  86.     t->cancel(0);
  87.     (void) result();
  88.     return (residual);
  89. }
  90.  
  91. char *
  92. CPUTimer::getName()
  93. {
  94.     return (t_name);
  95. }
  96.  
  97. CPUManager::CPUManager( CPU * cpu )
  98.     : ( CatName( CatName( MakeName( "CPUManager",this ), " for " ),
  99.              cpu->getName() ) )
  100. {
  101.     Debug("%s: Ctor.\n", getName());
  102.     Assert(cpu != 0);
  103.  
  104.     /*
  105.      * A CPUManager's work is never done...
  106.      */
  107.     for (;;) {
  108.  
  109.         /*
  110.          * Wait for something to do.
  111.          */
  112.         Debug("%s: sleeping.\n", getName(), this);
  113.         sleep();
  114.         Debug("%s: waking.\n", getName(), this);
  115.  
  116.         /*
  117.          * Stop and delete the timer.
  118.          * Remember the residual timeslice time.
  119.          */
  120.         int residual = 0;
  121.         if (cpu->cpuTimer != 0) {
  122.             cpu->cpuTimer->stop();
  123.             residual = cpu->cpuTimer->result();
  124.             delete cpu->cpuTimer;
  125.             cpu->cpuTimer = 0;
  126.         }
  127.  
  128.         /*
  129.          * Handle pending trap.
  130.          */
  131.         SoftwareException * thistrap = cpu->whichTrap;
  132.         if (thistrap != 0) 
  133.         {
  134.             Debug("%s: off to a handler.\n", getName(), this);
  135.             /* Software Traps stop current Process
  136.              * so the handle can be called directly
  137.              */
  138.             Assert(cpu->currentProcess->getState() == IDLE);
  139.             cpu->whichTrap = 0;
  140.             thistrap->handle(cpu,0);
  141.         }
  142.         /*
  143.          * Stop the current Process, if there is one.
  144.          */
  145.         else 
  146.         {
  147.             Process * currentProcess = cpu->currentProcess;
  148.             if ( currentProcess != 0 ) {
  149.                 Assert(currentProcess->getState() == RUNNING);
  150.                 Debug("%s: stop %s.\n",
  151.                     getName(), currentProcess->getName());
  152.                 currentProcess->stop();
  153.                 };
  154.         };
  155.  
  156.  
  157.         /*
  158.          * Handle pending interrupts.
  159.          */
  160.         int vector;
  161.         int vectorCount = 0;
  162.         while ( (vector = cpu->removeVector()) != -1 ) {
  163.             Assert(VectorValid(vector));
  164.             Exception * exception = cpu->getException(vector);
  165.             Assert(exception != 0);
  166.             Debug("%s: vector %d --> %s.\n",
  167.                 getName(), vector, exception->getName());
  168.             exception->handle(cpu,vector);
  169.             vectorCount++;
  170.         }
  171.         Debug("%s: handled %d vectors.\n", getName(), vectorCount);
  172.  
  173.         /*
  174.          * Start the (possibly changed) current Process.
  175.          */
  176.         Process * currentProcess = cpu->currentProcess;
  177.         if ( currentProcess != 0 ) {
  178.             Debug("%s: %s.\n", getName(),
  179.                   currentProcess->getName());
  180.             Assert(currentProcess->getState() == IDLE);
  181.             int time = residual;
  182.             if ( cpu->currentProcessChanged ) {
  183.                 Debug("%s: new.\n", getName());
  184.                 cpu->currentProcessChanged = 0;
  185.                 time = currentProcess->getQuantum();
  186.             }
  187.             if ( time != RunToCompletion ) {
  188.                 Assert(cpu->cpuTimer == 0);
  189.                 Assert(time > 0);
  190.                 cpu->cpuTimer = new CPUTimer( cpu, time );
  191.             }
  192.             Debug("%s: start %s (time: %d).\n",
  193.                 getName(), currentProcess->getName(), time);
  194.             currentProcess->start(cpu);
  195.         } else {
  196.             Debug("%s: no current Process.\n", getName());
  197.         }
  198.     }
  199.     NotReached();
  200. }
  201.  
  202. char *
  203. CPUManager::getName()
  204. {
  205.     return (t_name);
  206. }
  207.  
  208. /*
  209.  * We maintain a linked list of CPU's for debugging purposes.
  210.  * We also allocate unique CPU IDs for convenience.
  211.  */
  212.  
  213. static CPU * CPUList = 0;
  214. static int CPUCount = 0;
  215.  
  216. static int ClockStarted = 0;
  217.  
  218. CPU::CPU( char * name )
  219.     : ( name ? name : MakeName( "CPU", this ) )
  220. {
  221.     /*
  222.      * Initialize CPU fields (except manager, done last).
  223.      */
  224.     next = CPUList; CPUList = this;
  225.     id = CPUCount++;
  226.     currentProcess = 0;
  227.     idleProcess = 0;
  228.     currentProcessChanged = 0;
  229.     vectorQueue = new VectorQueue();
  230.     exceptionTable = new Exception * [VectorCount];
  231.     for ( int i = 0; i < VectorCount; i++ )
  232.         exceptionTable[i] = 0;
  233.     scheduler = 0;
  234.     whichTrap = 0;
  235.     Debug("%s::ctor: %d.\n", getName(), id);
  236.  
  237.     /*
  238.      * Build and install the ResetException to handle the ResetVector.
  239.      */
  240.     ResetException * resetException = new ResetException();
  241.     setException(ResetVector, resetException);
  242.  
  243.     /*
  244.      * Build and install the TimerException to handle the TimerVector.
  245.      */
  246.     TimerException * timerException = new TimerException();
  247.     setException(TimerVector, timerException);
  248.  
  249.     /*
  250.      * Build and install the TerminateException to handle the
  251.      * TerminateVector.
  252.      */
  253.     TerminateException * terminateException = new TerminateException();
  254.     setException(TerminateVector, terminateException);
  255.  
  256.     /*
  257.      * Start the clock, (first CPU only).
  258.      */
  259.     int mask = BlockClock();
  260.     if ( ! ClockStarted ) {
  261.         ClockStarted = 1;
  262.         UnblockClock(mask);
  263.         Debug("%s::ctor: Starting clock.\n", getName());
  264.         StartClock();
  265.     } else {
  266.         UnblockClock(mask);
  267.     }
  268.  
  269.  
  270.     /*
  271.      * Build manager.
  272.      */
  273.     cpuManager = new CPUManager(this);
  274.  
  275.     /*
  276.      * Wait for the manager to go to sleep.
  277.      * This avoids a race condition where interrupts sent to the
  278.      * CPU might refrain from waking up the manager (because it is
  279.      * still running before its initial sleep), then when the manager
  280.      * goes to sleep, there is the possibility that it might never
  281.      * be awoken to handle the pending interrupt.
  282.      */
  283.     while ( cpuManager->rdstate() == RUNNING ) {
  284.         Assert(thistask != 0);
  285.         thistask->delay( 0 );
  286.     }
  287.     Assert( cpuManager->rdstate() == IDLE );
  288.     Debug("%s::ctor: manager %s.\n", getName(), cpuManager->getName());
  289. }
  290.  
  291. CPU::~CPU()
  292. {
  293.     /*
  294.      * CPUs should not be destroyed, although I suppose they could.
  295.      */
  296.     NotReached();
  297. }
  298.  
  299. void
  300. CPU::setIdleProcess( Process * idleProcess )
  301. {
  302.     /*
  303.      * Set the idle Process.
  304.      */
  305.     Assert(idleProcess != 0);
  306.     Debug("%s: idle Process is %s.\n", getName(), idleProcess->getName());
  307.     Assert(idleProcess->getState() == IDLE);
  308.     Assert(CPU::idleProcess == 0);
  309.     CPU::idleProcess = idleProcess;
  310. }
  311.  
  312. void
  313. CPU::setScheduler( ProcessContainer * scheduler )
  314. {
  315.     /*
  316.      * Set the scheduler.
  317.      */
  318.     Assert(scheduler != 0);
  319.     Debug("%s: scheduler is %s.\n", getName(), scheduler->getName());
  320.     CPU::scheduler = scheduler;
  321. }
  322.  
  323. void
  324. CPU::setException( int vector, Exception * exception )
  325. {
  326.     /*
  327.      * Set the Exception for the specified vector.
  328.      */
  329.     Assert(VectorValid(vector));
  330.     Assert(exception != 0);
  331.     Assert(exceptionTable != 0);
  332.     Assert(exceptionTable[vector] == 0);
  333.     Debug("%s: set vector %d to %s.\n",
  334.         getName(), vector, exception->getName());
  335.     exceptionTable[vector] = exception;
  336. }
  337.  
  338. void
  339. CPU::interrupt( int vector )
  340. {
  341.     Debug("%s: interrupt vector %d.\n", getName(), vector);
  342.     Assert(VectorValid(vector));
  343.     Assert(exceptionTable != 0);
  344.     Assert(exceptionTable[vector] != 0);
  345.     Assert(vectorQueue != 0);
  346.  
  347.     /*
  348.      * Enqueue the vector.
  349.      * Wake up the manager, if necessary.
  350.      */
  351.     vectorQueue->add(vector);
  352.     int mask = BlockClock();
  353.     if ( cpuManager->rdstate() == IDLE )
  354.         cpuManager->delay(0);
  355.     UnblockClock(mask);
  356.  
  357.     /*
  358.      * Let someone else run.
  359.      * Necessary?  Probably not.
  360.      */
  361.     thistask->delay(0);
  362. }
  363.  
  364. void
  365. CPU::trap( SoftwareException * exception )
  366. {
  367.     Debug("%s: software trap %d.\n", getName(), (int) exception);
  368.     Assert(exception != 0);
  369.     Assert(!((ProcessTask *) thistask)->isPreemptable());
  370.  
  371.     /*
  372.      * Enqueue the vector.
  373.      * Wake up the manager, if necessary.
  374.      */
  375.     whichTrap = exception;
  376.     if ( cpuManager->rdstate() == IDLE )
  377.         cpuManager->delay(0);
  378.     /*
  379.      * Software traps block the running process immediately
  380.      * so the second loop keeps this Process busy until the Manager 
  381.      * stops this Process.
  382.      */
  383.     currentProcess->stop();
  384.     Debug("%s: software trap returns%d.\n", getName(), (int) exception);
  385. }
  386.  
  387. CPU::getID()
  388. {
  389.     /*
  390.      * Return the ID.
  391.      */
  392.     return (id);
  393. }
  394.  
  395. void
  396. CPU::add( Process * newProcess )
  397. {
  398.     /*
  399.      * Make the new Process the current Process.
  400.      * We expect that there is initially no current Process.
  401.      */
  402.     Assert(newProcess != 0);
  403.     Assert(currentProcess == 0);
  404.     Debug("%s: add %s.\n", getName(), newProcess->getName());
  405.     currentProcess = newProcess;
  406.     currentProcessChanged = 1;
  407. }
  408.  
  409. Process *
  410. CPU::remove()
  411. {
  412.     /*
  413.      * Remove and return the current Process.
  414.      */
  415.     Assert(currentProcess != 0);
  416.     Process * process = currentProcess;
  417.     currentProcess = 0;
  418.     currentProcessChanged = 1;
  419.     Debug("%s: remove %s.\n", getName(), process->getName());
  420.     return (process);
  421. }
  422.  
  423. int
  424. CPU::isEmpty()
  425. {
  426.     return (currentProcess == 0);
  427. }
  428.  
  429. int
  430. CPU::removeVector()
  431. {
  432.     /*
  433.      * Dequeue the next pending vector from the VectorQueue.
  434.      * Getting -1 means there are no pending vectors.
  435.      */
  436.     int vector = vectorQueue->remove();
  437.     Assert(VectorValid(vector) || (vector == -1));
  438.     return (vector);
  439. }
  440.  
  441. Exception *
  442. CPU::getException( int vector )
  443. {
  444.     /*
  445.      * Return the Exception corresponding to the specified vector.
  446.      */
  447.     Assert(VectorValid(vector));
  448.     Assert(exceptionTable != 0);
  449.     Exception * exception = exceptionTable[vector];
  450.     Assert(exception != 0);
  451.     return (exception);
  452. }
  453.  
  454. ProcessContainer *
  455. CPU::getScheduler()
  456. {
  457.     return (scheduler);
  458. }
  459.  
  460. int
  461. CPU::managerRunning()
  462. {
  463.     Assert(cpuManager != 0);
  464.     Assert(thistask != 0);
  465.     return (thistask == cpuManager);
  466. }
  467.  
  468. CPU *
  469. ThisCPU()
  470. {
  471.     int mask = BlockClock();
  472.     Assert(IsAProcessTask(thistask));
  473.     ProcessTask * pt = (ProcessTask *) thistask;
  474.     Process * p = pt->getProcess();
  475.     Assert(p != 0);
  476.     CPU * cpu = p->getCPU();
  477.     Assert(cpu != 0);
  478.     (void) UnblockClock(mask);
  479.     return (cpu);
  480. }
  481.